home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / program / cpp112.zoo / src / macro.c < prev    next >
C/C++ Source or Header  |  1994-07-07  |  12KB  |  483 lines

  1.  
  2. /*---------------------------------------------------------------------*\
  3. |                                    |
  4. | CPP -- a stand-alone C preprocessor                    |
  5. | Copyright (c) 1993 Hacker Ltd.        Author: Scott Bigham    |
  6. |                                    |
  7. | Permission is granted to anyone to use this software for any purpose    |
  8. | on any computer system, and to redistribute it freely, with the    |
  9. | following restrictions:                        |
  10. | - No charge may be made other than reasonable charges for repro-    |
  11. |     duction.                                |
  12. | - Modified versions must be clearly marked as such.            |
  13. | - The author is not responsible for any harmful consequences of    |
  14. |     using this software, even if they result from defects therein.    |
  15. |                                    |
  16. | macro.c -- do macro expansion                        |
  17. \*---------------------------------------------------------------------*/
  18.  
  19. #include <stddef.h>
  20. #include <string.h>
  21. #include <time.h>
  22. #include <stdlib.h>
  23. #include "global.h"
  24. #include "alloc.h"
  25.  
  26. static char SC_not_id[] = "parameter \"%s\" to defined() is not an identifier";
  27.  
  28. char *magic_words[] =
  29. {
  30.   "__STDC__",            /* the first three are particuarly magic -- */
  31.   "defined",            /* leave them where they are */
  32.   "__FLUFF__",
  33.   "__DATE__",
  34.   "__TIME__",
  35.   "__FILE__",
  36.   "__LINE__",
  37.   "__INCLUDE_LEVEL__",
  38. };
  39. int N_MWORDS = nelems(magic_words);
  40. int N_M2WORDS = 3;        /* number of "special" magic words */
  41.  
  42. /* mk_Macro() -- allocate and initialize a macro structure */
  43. Macro *mk_Macro()
  44. {
  45.   register Macro *M = alloc_Macro();
  46.  
  47.   M->flags = M->nargs = 0;
  48.   M->m_text = M->argnames = NULL;
  49.   M->next = NULL;
  50.   return M;
  51. }
  52.  
  53. /* free_Macro() -- clean up and deallocate a macro structure */
  54. void free_Macro(M)
  55.   register Macro *M;
  56. {
  57.   if (!M)
  58.     return;
  59.   if (M->m_text)
  60.     free_tlist(M->m_text);
  61.   if (M->argnames)
  62.     free_tlist(M->argnames);
  63.   dealloc_Macro(M);
  64. }
  65.  
  66. /*
  67.    magic_token() -- create a Token to be returned by expand_magic() below
  68. */
  69. static TokenP magic_token(type, text, l, T0)
  70.   int type;
  71.   const char *text;
  72.   long l;
  73.   TokenP T0;
  74. {
  75.   register TokenP T = mk_Token();
  76.  
  77.   set_ws(T, token_ws(T0));
  78.   if (type != STR_CON)
  79.     set_txt(T, text);
  80.   else {
  81.     char *u = mallok(strlen(text) + 3);
  82.  
  83.     (void)sprintf(u, "\"%s\"", text);
  84.     set_txt(T, u);
  85.     free(u);
  86.   }
  87.   T->type = type;
  88.   if (type == NUMBER)
  89.     T->val = l;
  90.   if (type == ID)
  91.     T->flags |= BLUEPAINT;
  92.   return T;
  93. }
  94.  
  95. /* expand_magic() -- expand a magic preprocessor constant */
  96. static TokenP expand_magic(T)
  97.   register TokenP T;
  98. {
  99.   static char buf[20];
  100.   int i;
  101.   register TokenP T1, tL;
  102.   Token tLH;
  103.  
  104.   for (i = 0; i < N_MWORDS; i++)
  105.     if (streq(token_txt(T), magic_words[i]))
  106.       break;
  107.   switch (i) {
  108.   case 0:            /* __STDC__ */
  109.     return magic_token(NUMBER, "1", 1L, T);
  110.   case 1:            /* defined */
  111.     tL = &tLH;
  112.     tL->next = NULL;
  113.     buf[0] = '0';
  114.     buf[1] = '\0';
  115.     T1 = token();
  116.     if (T1->type == STOP) {
  117.       push_tlist(T1);
  118.       error("defined() has no parameter");
  119.       goto nope;
  120.     }
  121. #if 0
  122.     tL = tL->next = T1;
  123. #endif
  124.     if (T1->type == ID) {
  125.       if (lookup(token_txt(T1), T1->hashval))
  126.     buf[0] = '1';
  127.       free_token(T1);
  128.     } else if (T1->type == LPAREN) {
  129.       free_token(T1);
  130.       T1 = token();
  131. #if 0
  132.       tL = tL->next = T1;
  133. #endif
  134.       if (T1->type == STOP) {
  135.     push_tlist(T1);
  136.     error("unterminated defined() macro");
  137.     goto nope;
  138.       } else if (T1->type == ID) {
  139.     if (lookup(token_txt(T1), T1->hashval))
  140.       buf[0] = '1';
  141.     free_token(T1);
  142.     T1 = token();
  143. #if 0
  144.     tL = tL->next = T1;
  145. #endif
  146.     if (T1->type != RPAREN) {
  147.       push_tlist(T1);
  148.       error("missing `)' in defined()");
  149.       goto nope;
  150.     }
  151.     free_token(T1);
  152.       } else {
  153.     error(SC_not_id, token_txt(T1));
  154.     free_token(T1);
  155.     goto nope;
  156.       }
  157.     } else {
  158.       error(SC_not_id, token_txt(T1));
  159.       free_token(T1);
  160.       goto nope;
  161.     }
  162. #if 0
  163.     free_tlist(tLH.next);
  164. #endif
  165.     return magic_token(NUMBER, buf, (long)(*buf == '1'), T);
  166.   nope:
  167. #if 0
  168.     push_tlist(tLH.next);
  169. #endif
  170.     return magic_token(NUMBER, "0", 0L, T);
  171.   case 2:            /* __FLUFF__ */
  172.     return magic_token(NUMBER, "1", 1L, T);
  173.   case 3:            /* __DATE__ */
  174.     return magic_token(STR_CON, date_string, 0L, T);
  175.   case 4:            /* __TIME__ */
  176.     return magic_token(STR_CON, time_string, 0L, T);
  177.   case 5:            /* __FILE__ */
  178.     return magic_token(STR_CON, cur_file, 0L, T);
  179.   case 6:            /* __LINE__ */
  180.     sprintf(buf, "%lu", this_line);
  181.     return magic_token(NUMBER, buf, this_line, T);
  182.   case 7:            /* __INCLUDE_LEVEL__ */
  183.     sprintf(buf, "%lu", include_level);
  184.     return magic_token(NUMBER, buf, include_level, T);
  185.   default:
  186.     bugchk("unknown magic word %s", token_txt(T));
  187.   }
  188. }
  189.  
  190. /*
  191.    get_args() -- read in the actual arguments of a macro expansion. |mname|
  192.    is the name of the macro being expanded; |nargs| is the number of
  193.    arguments to read.
  194. */
  195. static TokenP *get_args(mname, nargs)
  196.   char *mname;
  197.   int nargs;
  198. {
  199.   int cur_arg, par_level = 0;
  200.   register TokenP T, L;
  201.   register TokenP *args;
  202.   Token head;
  203.  
  204.   args = (TokenP *) mallok((nargs ? nargs : 1) * sizeof (TokenP));
  205.   for (cur_arg = 0; cur_arg < nargs || cur_arg == 0; cur_arg++)
  206.     args[cur_arg] = NULL;
  207.   cur_arg = 0;
  208.   L = &head;
  209.   L->next = NULL;
  210.   change_mode(SLURP, 0);
  211.   for (;;) {
  212.     T = token();
  213.     switch (T->type) {
  214.     case STOP:
  215.       push_tlist(T);
  216.       error("unterminated macro \"%s\"", mname);
  217.       goto out_loop;
  218.     case EOL:
  219.       free_token(T);
  220.       continue;
  221.     case LPAREN:
  222.       par_level++;
  223.       break;
  224.     case RPAREN:
  225.       if (--par_level < 0) {
  226.     free_token(T);
  227.     goto out_loop;
  228.       }
  229.       break;
  230.     case COMMA:
  231.       if (par_level == 0) {
  232.     free_token(T);
  233.     args[cur_arg++] = head.next;
  234.     L = &head;
  235.     L->next = NULL;
  236.     continue;
  237.       }
  238.       break;
  239.     }
  240.     if (cur_arg < nargs)
  241.       L = L->next = T;
  242.   }
  243. out_loop:
  244.   change_mode(0, SLURP);
  245.   if (head.next || cur_arg > 0)
  246.     args[cur_arg++] = head.next;
  247.   if (cur_arg != nargs)
  248.     error("macro \"%s\" declared with %d arg%s, used with %d",
  249.       mname, nargs, (nargs == 1 ? "" : "s"), cur_arg);
  250.   return args;
  251. }
  252.  
  253. /*
  254.    stringize() -- create a string literal representing the token list |T|
  255. */
  256. static TokenP stringize(T)
  257.   TokenP T;
  258. {
  259.   char *buf;
  260.   register char *s, *t;
  261.   size_t buflen, i;
  262.   ptrdiff_t dp;
  263.   register TokenP tt;
  264.   TokenP t0;
  265.  
  266.   s = buf = mallok(buflen = 80);
  267.   *s++ = '"';
  268.   for (tt = T; tt; tt = tt->next) {
  269.     i = 2 * strlen(token_txt(tt)) + 2;
  270.     if (tt != T)
  271.       i += strlen(token_ws(tt));
  272.     s = grow(&buf, &buflen, s, i);
  273.     if (tt != T)
  274.       for (t = token_ws(tt); *t; t++)
  275.     *s++ = *t;
  276.     for (t = token_txt(tt); *t; t++) {
  277.       if (*t == '\\' || *t == '"')
  278.     *s++ = '\\';
  279.       *s++ = *t;
  280.     }
  281.   }
  282.   *s++ = '"';
  283.   *s = '\0';
  284.   t0 = mk_Token();
  285.   t0->type = STR_CON;
  286.   set_txt(t0, buf);
  287.   free(buf);
  288.   set_ws(t0, token_ws(T));
  289.   return t0;
  290. }
  291.  
  292. /*
  293.    expand() -- expand the macro definition |M| of the Token |T|.  Push the
  294.    resulting token list onto the token stream.
  295.  
  296. WARNING:  _Always_ check the BLUEPAINT flag before calling expand(), or
  297.    you'll end up with either the wrong answer or an infinite loop, or both.
  298.    At the moment this is not a concern, since only exp_token() and
  299.    expand_tlist() call expand().
  300.  
  301. NOTE:  |T| should be free_token()'d after the call to expand().
  302. */
  303. void expand(T, M)
  304.   TokenP T;
  305.   register Macro *M;
  306. {
  307.   Token head1, head2, mhead;
  308.   register TokenP t1, pt1, t2 = &head2;
  309.   TokenP pt2 = &head1, *args, *exp_args, *str_args;
  310.   int n;
  311.  
  312.   head1.flags = head2.flags = mhead.flags = 0;
  313.   head1.next = &head2;
  314.   head2.next = NULL;
  315.   mhead.next = M->m_text;
  316.   if (M->flags & MARKED) {
  317.     t1 = copy_token(T);
  318.     t1->flags |= BLUEPAINT;
  319.     push_tlist(t1);
  320.     return;
  321.   }
  322.   if (M->flags & MAGIC) {
  323.     push_tlist(expand_magic(T));
  324.     return;
  325.   }
  326.   if (M->flags & HASARGS) {
  327.     t1 = token();
  328.     if (t1->type == STOP) {
  329.  
  330.       /*
  331.          Special case:  we can't expand this token now, but if it is placed
  332.          before a left paren, we can expand it later.  Mark it to be
  333.          unpai